"use strict"

/**
 * @加密解密方法库
 * 直接使用globalThis.crypto对象的加密/解密实现
 * 不依赖node库，因此具有最广泛的适用性
 *   1. aesEncrypt() AES加密
 *   2. aesDecrypt() AES解密
 *   3. genIv() 以初始字符串生成12位iv
 *   4. importAesKey() 导入数值以生成128位AES密钥
 *   5. genAesKey() 随机生成AES密钥
 *   6. bufferToArray() ArrayBuffer转Array数组
 */


/**
 * @全局对象
 * 加密相关的抽象工具类
 * 方便本模块的方法直接调用
 */
// crypto加密对象
const crypto = globalThis.crypto
// 编码器
const encoder = new TextEncoder()
// 解码器
const decoder = new TextDecoder()


/**
 * aesEncrypt
 * @function AES加密
 * @param { String } plainText 明文
 * @param { CryptoKey } key 密钥
 * @returns { Promise<ArrayBuffer> } 密文ArrayBuffer
 */
export async function aesEncrypt(plainText, key) { try {
  // 明文字符串转码为ArrayBuffer
  const plainBuffer = encoder.encode(plainText)
  // 获得iv
  const iv = genIv(key)
  // 加密
  const cipherBuffer = await crypto.subtle.encrypt(
    // AES算法，iv为全局IV
    { name: "AES-GCM", iv: iv },
    // 密钥
    key,
    // 明文的ArrayBuffer对象
    plainBuffer
  )
  // 返回加密结果
  return cipherBuffer
} catch (error) {
  console.error("aesEncrypt()报错：", error)
}}


/**
 * aesDecrypt
 * @function AES解密
 * @param { ArrayBuffer } cipherBuffer 密文
 * @param { CryptoKey } key 密钥
 * @returns { Promise<String> } 返回解密结果
 */
export async function aesDecrypt(cipherBuffer, key) { try {
  // 获得iv
  const iv = genIv(key)
  // 解密
  const plainBuffer = await crypto.subtle.decrypt(
    // 算法
    { name: "AES-GCM", iv: iv },
    // 密钥
    key,
    // 密文的ArrayBuffer对象
    cipherBuffer
  )
  // ArrayBuffer转码为明文字符串
  const plaintext = decoder.decode(plainBuffer)
  // 返回解密结果
  return plaintext
} catch (error) {
  console.error("aesDecrypt()报错：", error)
}}


/**
 * importAesKey
 * @function 导入数值以生成128位AES密钥
 * @param { String } originKey 初始密钥
 * @returns { Promise<CryptoKey> } 返回生成的密钥
 */
export async function importAesKey(originKey) { try {
  // 构造16位密钥ArrayBuffer
  const keyBuffer = new Uint8Array(16)
  // 把字符串转码为ArrayBuffer
  const keyStrBuffer = encoder.encode(originKey)
  // 复制keyStrBuffer的值到keyBuffer中
  keyBuffer.set(keyStrBuffer.slice(0, 16))
  // 构造AES密钥
  const aesKey = await crypto.subtle.importKey(
    // 导入密钥的格式，"raw"即ArrayBuffer
    "raw",
    // 处理好的密钥ArrayBuffer
    keyBuffer,
    // AES算法 + 密钥长度
    { name: "AES-GCM", length: 128 },
    // 是否可导出
    false,
    // 可用的操作：加密、解密
    ["encrypt", "decrypt"]
  )
  // 返回生成的密钥
  return aesKey
} catch (error) {
  console.error("importAesKey()报错：", error)
}}


/**
 * genAesKey
 * @function 随机生成AES密钥
 * @param { Number } [length] 密钥长度，默认128位
 * @returns { Promise<CryptoKey> } 返回生成的密钥
 */
export async function genAesKey(length = 128) { try {
  // 构造AES密钥
  const key = await crypto.subtle.generateKey(
    // AES算法 + 密钥长度
    { name: "AES-GCM", length },
    // 是否可导出
    false,
    // 可用的操作：加密、解密
    ["encrypt", "decrypt"]
  )
  // 返回生成的密钥
  return key
} catch (error) {
  console.error("genAesKey()报错：", error)
}}


/**
 * genIv
 * @function 以初始字符串生成12位iv
 * @param { String } originStr 初始字符串
 * @returns { Uint8Array<ArrayBuffer> } 返回生成的iv
 */
export function genIv(originStr) { try {
  // 构造12位iv ArrayBuffer
  const iv = new Uint8Array(12)
  // 把字符串转码为ArrayBuffer
  const strBuffer = encoder.encode(originStr)
  // 复制keyStrBuffer的值到keyBuffer中
  iv.set(strBuffer.slice(0, 12))
  // 返回生成的iv
  return iv
} catch (error) {
  console.error("genIv()报错：", error)
}}


/**
 * bufferToArray
 * @function ArrayBuffer转Array数组
 * @param { ArrayBuffer } buffer buffer对象
 * @returns { Array<Number> } Array数组
 */
export function bufferToArray(buffer) { try {
  // 以DataView处理ArrayBuffer数据
  const dataView = new DataView(buffer)
  // 构造Array数组
  const array = []
  // 遍历DataView的每个字节
  for (let i = 0; i < dataView.byteLength; i++) {
    // 获取字节中的数值，放入Array数组中
    array.push(dataView.getUint8(i))
  }
  // 返回Array数组
  return array
} catch (error) {
  console.error("bufferToArray()报错：", error)
}}
